#-*- coding:utf-8 -*-
'''
calculate score_pfd : product ,feature, score_pfd, num_of_reviews, update_date 
'''
'''
there is still has score_pdf even when num_reviews is 0
'''
import re
import sys
import traceback
from numpy import inf
from datetime import date, datetime, timedelta

import db_util

'''
def indexOf(review, feature):
	features = feature.split(', ')
	if len(features)==1:
		return review.find(feature)
	index_sum = 0
	for f in features:
		index_sum += review.find(f)
	return float(index_sum/len(features))

def dis(review, feature, sentiment):
	index_1 = indexOf(review, feature)
	index_2 = review.find(sentiment)
	if index_1!= int(-1) and index_2!= int(-1):
		return abs(index_1-index_2)
	return int(-1)#review does not contain sentiment

def cal_score(review, feature, sentiment):
	distance = dis(review, feature, sentiment[0])
	if distance == int(-1) or distance == int(0):
		return 0
	return float(sentiment[1])/float(distance)
'''

def search_feature(review, feature):
	features = feature.split(', ')
	pattern = ''
	for feature in features:
		pattern += feature+'.*'
	pattern = pattern[:-2]
	result = re.search(pattern, review)
	if result:
		return (result.start()+result.end())/2.0
	else:
		return float(inf)

def search_sentiment(review, sentiment):
	pos = [(m.start()+m.end())/2.0 for m in re.finditer('(?='+sentiment+')', review)]
	return pos

def dis(index_feature, index_sentiment):
	dis_min = 0.0
	if len(index_sentiment) == 1:
		dis_min = abs(index_feature - index_sentiment[0])
	else:
		dis_min = float(inf)
		for index in index_sentiment:
			dis = abs(index_feature - index)
			if dis < dis_min:
				dis_min = dis
	if dis_min == 0.0:
		dis_min = 1.0
	return dis_min

def cal_score(review, feature, sentiment):
	index_feature = search_feature(review, feature)
	index_sentiment = search_sentiment(review, sentiment[0])
	if index_feature == float(inf) or len(index_sentiment)==0:#no feature or sentiment in the review
		return 0.0
	else:
		return float(sentiment[1])/dis(index_feature, index_sentiment)

def query_reviews(product, update_date, category, db):
	reviews = []
	stmt = ("select distinct(content) from review where product_id = %s and time <= %s")
	result = db.cur.execute(stmt, (product, update_date))
	if result:
		result = db.cur.fetchall()
		for obj in result:
			reviews.append(obj[0])
	return reviews

def is_firstday_score_pfd(update_date, category, db):
	stmt = ("select * from score_pfd where update_date < %s and category = %s limit 1")
	result = db.cur.execute(stmt, (update_date, category))
	if result:
		return False
	return True

def query_reviews_smday(product, update_date, category, db):
	reviews = []
	stmt = ("select distinct(content) from review where product_id = %s and time = %s")
	result = db.cur.execute(stmt, (product, update_date))
	if result:
		result = db.cur.fetchall()
		for obj in result:
			reviews.append(obj[0])
	return reviews

def insert_score_pfd(product, feature, score_pfd, num_reviews, update_date, category, db):
	stmt = ("insert into score_pfd "
		"(product_id, feature, score, num_reviews, update_date, category) values (%s,%s,%s,%s,%s,%s)")
	try:
		db.cur.execute(stmt, (product, feature, score_pfd, num_reviews, update_date, category))
		db.conn.commit()
	except:
		traceback.print_exc()
		db.conn.rollback()

def update_score_pfd(product, update_date, category, features, sentiments, db):
	first_day = is_firstday_score_pfd(update_date, category, db)
	if not first_day:
		reviews = query_reviews_smday(product, update_date, category, db)
	else:
		reviews = query_reviews(product, update_date, category, db)
	for feature in features:
		score_pfd = 0.0
		num_reviews = len(reviews)
		for review in reviews:
			for sentiment in sentiments:
				score_pfd += cal_score(review, feature, sentiment)
		score_pfd = score_pfd/num_reviews if num_reviews != 0 else 0.0
		insert_score_pfd(product, feature, score_pfd, num_reviews, update_date, category, db)

'''
calculate score_pf : product, feature, score_pf, num_of_reviews, update_date
'''

def is_firstday(update_date, category, db):
	stmt = ("select * from score_pf where update_date < %s and category = %s limit 1")
	result = db.cur.execute(stmt, (update_date, category))
	if result:
		return False
	return True

def query_score_pf(product, feature, category, update_date, db):
	stmt = ("select score, num_reviews from score_pf "
		"where product_id=%s and feature=%s and category=%s and update_date=%s")
	result = db.cur.execute(stmt, (product, feature, category, update_date))
	if result:
		return db.cur.fetchone()
	else:
		return (0.0, 0)

def query_score_pfd(product, feature, category, update_date, db):
	stmt = ("select score, num_reviews from score_pfd "
		"where product_id=%s and feature=%s and category=%s and update_date=%s")
	result = db.cur.execute(stmt, (product, feature, category, update_date))
	if result:
		return result.fetchone()
	else:
		return (0.0, 0)

def query_score_pfd_to_date(product, feature, category, update_date, db):
	stmt = ("select score, num_reviews from score_pfd "
		"where product_id=%s and feature=%s and category=%s and update_date<=%s")
	result = db.cur.execute(stmt, (product, feature, category, update_date))
	if result:
		return db.cur.fetchall()
	else:
		return [(0.0, 0)]

def insert_score_pf(product, feature, score_pf, num_reviews, update_date, category, db):
	stmt = ("insert into score_pf "
		"(product_id, feature, score, num_reviews, update_date, category) values (%s,%s,%s,%s,%s,%s)")
	try:
		db.cur.execute(stmt, (product, feature, score_pf, num_reviews, update_date, category))
		db.conn.commit()
	except:
		traceback.print_exc()
		db.conn.rollback()

def update_score_pf(product, update_date, category, features, db):
	first_day = is_firstday(update_date, category, db)
	for feature in features:
		score_pf = 0.0
		num_reviews = 0
		if not first_day:
			score_pf_ystday, num_reviews_ystday = query_score_pf(product, feature, category, update_date-timedelta(days=1), db)
			score_pfd_today, num_reviews_today = query_score_pfd(product, feature, category, update_date, db)

			num_review = num_reviews_ystday + num_reviews_today
			score_pf = (score_pf_ystday*num_reviews_ystday + score_pfd_today*num_reviews_today)/num_reviews if num_reviews != 0 else 0.0
		else:
			result_list = query_score_pfd_to_date(product, feature, category, update_date, db)

			for score_pfd, num_reviews_smday in result_list:
				score_pf += score_pfd * num_reviews_smday
				num_reviews += num_reviews_smday
			score_pf = score_pf / num_reviews if num_reviews != 0 else 0.0

		insert_score_pf(product, feature, score_pf, num_reviews, update_date, category, db)

'''
calculate score_p
'''
def insert_score_p(product, score_p, update_date, category, db):
	stmt = ("insert into score_p "
		"(product_id, score, update_date, category) values (%s,%s,%s,%s)")
	try:
		db.cur.execute(stmt, (product, score_p, update_date, category))
		db.conn.commit()
	except:
		traceback.print_exc()
		db.conn.rollback()

def update_score_p(product, update_date, category, features, db):
	score_p = 0.0
	for feature in features:
		score_pf_obj = query_score_pf(product, feature, category, update_date, db)
		score_p += float(score_pf_obj[0])
	score_p = score_p / len(features) if len(features) != 0 else 0.0

	insert_score_p(product, score_p, update_date, category, db)

'''
update category
'''

def query_products(update_date, category, db):
	products = []
	stmt = ("select distinct(product_id) from product where category = %s and update_date = %s")
	result = db.cur.execute(stmt, (category, update_date))
	if result:
		result = db.cur.fetchall()
		for obj in result:
			products.append(obj[0])
	return products

def query_features(category, db):
	features = []
	stmt = ("select distinct(feature) from feature where category = %s")
	result = db.cur.execute(stmt, (category))
	if result:
		result = db.cur.fetchall()
		for obj in result:
			features.append(obj[0])
	return features

def query_sentiments(category, db):
	sentiments = []
	stmt = ("select word, weights from sentiment_word "
		"where category = %s")
	result = db.cur.execute(stmt, (category))
	if result:
		result = db.cur.fetchall()
		sentiments = result
	return sentiments

def update_cellphone(update_date, db):
	category = 'cellphone'
	features = query_features(category, db)
	sentiments = query_sentiments(category, db)
	products = query_products(update_date, category, db)
	for product in products:
		update_score_pfd(product, update_date, category, features, sentiments, db)
		update_score_pf(product, update_date, category, features, db)
		update_score_p(product, update_date, category, features, db)

def update_camera(update_date, db):
	category = 'digital_camera'
	features = query_features(category, db)
	sentiments = query_sentiments(category, db)
	products = query_products(update_date, category, db)
	for product in products:
		update_score_pfd(product, update_date, category, features, sentiments, db)
		update_score_pf(product, update_date, category, features, db)
		update_score_p(product, update_date, category, features, db)

def update_dslr(update_date, db):
	category = 'dslr'
	features = query_features(category, db)
	sentiments = query_sentiments(category, db)
	products = query_products(update_date, category, db)
	for product in products:
		update_score_pfd(product, update_date, category, features, sentiments, db)
		update_score_pf(product, update_date, category, features, db)
		update_score_p(product, update_date, category, features, db)

def update_micro_dslr(update_date, db):
	print 'micro_dslr'
	category = 'micro_dslr'
	features = query_features(category, db)
	sentiments = query_sentiments(category, db)
	products = query_products(update_date, category, db)
	for product in products:
		update_score_pfd(product, update_date, category, features, sentiments, db)
		update_score_pf(product, update_date, category, features, db)
		update_score_p(product, update_date, category, features, db)

if __name__ == '__main__':
	if len(sys.argv) == 1:
		print '缺少参数'
		sys.exit()
	else:
		#update_date = datetime.now().date()
		update_date = date(2015,6,26)
		db = db_util.db_manager()

		category = sys.argv[1]
		if category == 'cellphone':
			update_cellphone(update_date, db)
		elif category == 'digital_camera':
			update_camera(update_date, db)
		elif category == 'dslr':
			update_dslr(update_date, db)
		elif category == 'micro_dslr':
			update_micro_dslr(update_date, db)